﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SSharp.Core.DataTypes {
	/// <summary>
	/// A scheme promise is a basically a C# Func[T] wrapped in a way that it will only ever evaluate once.
	/// After the first time it is requested, the value is saved returned again the next time(s).
	/// </summary>
	public class Promise {
		private Func<dynamic> func;
		private Object locker;
		private dynamic value;

		public Promise(Func<dynamic> func) {
			this.func = func;
			locker = new Object();
		}

		/// <summary>
		/// Returns the promised value. Will return the same value if called multiple times.
		/// </summary>
		public dynamic Value {
			get {
				if (func != null) {
					ForcePromise();
				}
				return value;
			}
		}

		/// <summary>
		/// Forces the promise to be calculated
		/// </summary>
		private void ForcePromise() {
			lock (locker) {
				if (func != null) {
					value = func();
					func = null;
					// we're never going to use the locker again - no need to keep a reference.
					locker = null;
				}
			}
		}

		/// <summary>
		/// If the given value is a promise, forces it and returns its value.
		/// Otherwise, returns the given value unchanged.
		/// </summary>
		public static dynamic ForcePromise(object promise) {
			if (promise is Promise) {
				promise = ((Promise)promise).Value;
			}
			return promise;
		}

		public override string ToString() {
			return "<Promise " + GetHashCode() + ">";
		}
	}
}
